/******************************************************************************
Module:  AsyncEnumerator.cs
Notices: Copyright (c) 2006-2007 by Jeffrey Richter and Wintellect
******************************************************************************/


using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading;


///////////////////////////////////////////////////////////////////////////////


//internal class DebuggerStepThroughAttribute : Attribute { }


///////////////////////////////////////////////////////////////////////////////


namespace Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading.AsyncProgModel {
   //[DebuggerStepThrough]
   public partial class AsyncEnumerator {
      #region Static members
      // One delegate for ALL instances of this class
      private static SendOrPostCallback s_syncContextResumeIterator = SyncContextResumeIterator;
      private static void SyncContextResumeIterator(Object asyncEnumerator) {
         // This method calls the desired object's MoveNext method 
         // via the SynchronizationContext's desired thread
         ((AsyncEnumerator)asyncEnumerator).ResumeIterator(false);
      }
      #endregion

      #region Instance fields
      // Save the SynchronizationContext used to call OnResumeIterator
      private SynchronizationContext m_syncContext = null;
      public SynchronizationContext SyncContext {
         get { return m_syncContext; }
         set { m_syncContext = value; }
      }

      // The collection of completed async operations
      private readonly List<AsyncOp> m_inbox = new List<AsyncOp>();

      // The Wait and Inbox counters that are atomically manipulated
      protected WaitAndInboxCounts m_waitAndInboxCounts = new WaitAndInboxCounts();

      // Marker indicating what items to discard up to. All items with 
      // markers <= m_discardOpsUpTo are rejected/discarded from the inbox
      // Operation markers start at 0 which is why this is initialized to -1
      private Int32 m_discardOpsUpToMarker = -1;

      // The cache of AsyncOp objects that get reused to avoid lotscreate lots of these objects
      private AsyncOpCache m_asyncOpCache = new AsyncOpCache();

      private readonly AsyncEnumeratorOptions m_options = AsyncEnumeratorOptions.None;

      private Boolean m_throwOnMissingDiscardMarker = false;
      public Boolean ThrowOnMissingDiscardMarker { get { return m_throwOnMissingDiscardMarker; } set { m_throwOnMissingDiscardMarker = value; } }

      // The IEnumerator object that we call MoveNext/Current/Dispose over
      protected IEnumerator<Int32> m_enumerator;

      // The IAsyncResult object that allows the iteration to execute asynchronously
      protected AsyncResult m_asyncResult = null;
      #endregion

      #region Constructors
      public AsyncEnumerator() { m_waitAndInboxCounts.Initialize(); }
      public AsyncEnumerator(AsyncEnumeratorOptions options)
         : this() {
         if (((m_options = options) & AsyncEnumeratorOptions.CancelAllowed) != 0)
            m_cancelSignal = new SignalAlert<Object>();
      }
      #endregion

      #region Execute, BeginExecute and EndExecute
      public void Execute(IEnumerator<Int32> enumerator) {
         EndExecute(BeginExecute(enumerator, null, null));
      }

      public IAsyncResult BeginExecute(IEnumerator<Int32> enumerator, AsyncCallback callback) {
         return BeginExecute(enumerator, callback, null);
      }

      public IAsyncResult BeginExecute(IEnumerator<Int32> enumerator, AsyncCallback callback, Object state) {
         if (Interlocked.CompareExchange(ref m_enumerator, enumerator, null) != null)
            throw new InvalidOperationException("This object is already enumerating; use a different object for each enumerator.");

         m_asyncResult = OnContructAsyncResult(callback, state);
         ResumeIterator(true); // Start the enumeration
         return m_asyncResult;
      }

      public void EndExecute(IAsyncResult result) { m_asyncResult.EndInvoke(); }

      protected virtual AsyncResult OnContructAsyncResult(AsyncCallback callback, Object state) {
         return new AsyncResult(callback, state, this);
      }
      protected virtual void OnCompleteAsyncResult() {
         m_asyncResult.SetAsCompleted(null, false);
      }
      #endregion

      #region Members called by Iterator
      public static AsyncEnumerator GetAsyncEnumerator() { return t_thisAsyncEnumerator; }

      /// <summary>
      /// Pass this to a BegixXxx method's AsyncCallback argument to have the operation
      /// complete to advance the enumerator.
      /// </summary>
      /// <param name="result">The IAsyncResult representing the result of the operation.</param>
      public AsyncCallback End() {
         if (m_throwOnMissingDiscardMarker)
            throw new InvalidOperationException("Discard marker must be passed to End.");
         return m_asyncOpCache.Extract(this);
      }
      #endregion

      #region Internal Infrastructure
      [ThreadStatic]
      protected static AsyncEnumerator t_thisAsyncEnumerator;

      protected void ResumeIterator(Boolean calledFromArbitraryThread) {
         // If called from any thread and m_syncContext is null, then 
         // this call is OK and this thread can call the enumerator's MoveNext
         if (calledFromArbitraryThread && m_syncContext != null) {
            // Call this function (MoveNext) using the 
            // initializing thread's synchronization context
            m_syncContext.Post(s_syncContextResumeIterator, this);
            return;
         }

         Boolean iteratorNotInAfterState = false;
         Exception exception = null;
         try {
            // Save a reference to this AsyncEnumerator(-derived) object in thread-local storage. See the static GetAsyncEnumerator method
            t_thisAsyncEnumerator = this;

            // While there are more operations to perform...
            while (iteratorNotInAfterState = m_enumerator.MoveNext()) {
               // Get the value returned from the enumerator
               UInt16 numbersOpsToWaitFor = checked((UInt16)m_enumerator.Current);

               // If inbox has less than the number of items requested, keep the iterator suspended
               if (!m_waitAndInboxCounts.AtomicSetWait(numbersOpsToWaitFor)) break;
            }
         }
         catch (Exception e) {
            exception = e;
            iteratorNotInAfterState = false;
         }
         finally {
            // The iterator is done (after), perform final cleanup
            if (!iteratorNotInAfterState) {
               // Automatically discard any and all uncompleted operations
               DiscardOpsUpTo(Int32.MaxValue);

               // The iterator has exited (in 'after' state), execute the iterator's finally code
               m_enumerator.Dispose();

               // Complete our IAsyncResult indicating that enumeration is done
               if (exception != null) m_asyncResult.SetAsCompleted(exception, false);
               else OnCompleteAsyncResult();
            }
         }
      }
      #endregion

      #region Inbox Methods
      /// <summary>
      /// Called internally when an async operation completes
      /// </summary>
      /// <param name="asyncOp">The AsyncOp that wraps the non-cancelable or cancelable async operation.</param>
      private void EnqueueCompletedOpToInbox(AsyncOp asyncOp) {
         // Try to add this item to the inbox
         if (TryEnqueueCompletedOpToInbox(asyncOp)) {
            // If successful, add 1 to inbox. If this thread detects that 
            // the inbox has enough items in it; this thread should call MoveNext
            if (m_waitAndInboxCounts.AtomicIncrementInbox()) ResumeIterator(true);
         }
      }

#if false
      private void ClearAsyncResults() {
         lock (m_inbox) { m_inbox.Clear(); }
      }
#endif

      /// <summary>
      /// Rejects a completed AsyncOp if its marker is <= the current marker; if not rejected, the AsyncOp is added to the inbox.
      /// </summary>
      /// <param name="acw">The completed AsyncOp</param>
      /// <returns>True if the AsyncOp was added to the inbox; false if it was rejected.</returns>
      private Boolean TryEnqueueCompletedOpToInbox(AsyncOp asyncOp) {
         lock (m_inbox) {
            // Discard this result if it is below the discard marker
            if (asyncOp.DiscardMarker <= m_discardOpsUpToMarker) {
               asyncOp.SelfComplete();
               return false;
            }
            m_inbox.Add(asyncOp);
            return true;
         }
      }

      /// <summary>
      /// Dequeues a completed AsyncOp's IAsyncResult object from the inbox.
      /// </summary>
      /// <returns>The completed AsyncOp's IAsyncResult object.</returns>
      public IAsyncResult DequeueAsyncResult() {
         lock (m_inbox) {
            AsyncOp asyncOp = m_inbox[0];	// Extract AsyncOps in FIFO order
            m_inbox.RemoveAt(0);
            IAsyncResult result = asyncOp.AsyncResult;   // Save the IAsyncResult to return to the caller
            m_asyncOpCache.Insert(asyncOp);      // Put the AsyncOp back in the cache to be reused
            return result;
         }
      }

      /// <summary>
      /// Discards previously-completed AsyncOp objects from the inbox if their marker <= the specifed marker
      /// </summary>
      /// <param name="marker">Indicates which completed AsyncOp objects to discard.</param>
      /// <returns>The number of AsyncOp objects discarded from the inbox.</returns>
      private Int32 DiscardAsyncResultsUpToMarker(Int32 discardMarker) {
         Int32 numRemoved = 0;
         lock (m_inbox) {
            for (Int32 n = 0; n < m_inbox.Count; n++) {
               AsyncOp asyncOp = m_inbox[n];
               if (asyncOp.DiscardMarker <= discardMarker) {
                  asyncOp.SelfComplete();
                  m_inbox.RemoveAt(n--);
                  numRemoved++;
                  m_asyncOpCache.Insert(asyncOp);      // Put the AsyncOp back in the cache to be reused
               }
            }
         }
         return numRemoved;
      }
      #endregion

      #region Cancelation Support
      public void DiscardOpsUpTo(Int32 discardMarker) {
         // Reject any more results <= this marker from the Inbox
         Int32 oldDiscardMarker = InterlockedEx.Max(ref m_discardOpsUpToMarker, discardMarker);
         if (oldDiscardMarker > discardMarker)
            throw new ArgumentOutOfRangeException(
               String.Format("Discard marker ({0}) must be > {1}",
                  discardMarker, oldDiscardMarker));

         // Discard any results <= this marker from the Inbox
         Int32 numRemoved = DiscardAsyncResultsUpToMarker(discardMarker);

         // Update the Inbox counter to reflect the number of discarded items
         m_waitAndInboxCounts.AtomicDecrementInbox(numRemoved);
      }
      #endregion
   }
}


///////////////////////////////////////////////////////////////////////////////



namespace Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading.AsyncProgModel {
   [Flags]
   public enum AsyncEnumeratorOptions {
      None = 0x00000000,
      CancelAllowed = 0x00000001,
   }
}


///////////////////////////////////////////////////////////////////////////////


namespace Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading.AsyncProgModel {
   public partial class AsyncEnumerator {
      #region Countdown Timer Methods
      // Used for cancellation support
      private SignalAlert<Object> m_cancelSignal = null;

      // Used for countdown timer support
      private CountdownTimer m_countdownTimer = null;

      public void SetTimeout(Int32 discardMarker, Int32 milliseconds) {
         m_countdownTimer = new CountdownTimer();
         m_countdownTimer.BeginCountdown(milliseconds,
            this.EndVoid(discardMarker, this.EndTimeout), m_countdownTimer);
      }
      private void EndTimeout(IAsyncResult result) {
         ((CountdownTimer)result.AsyncState).EndCountdown(result);
      }
      public Boolean IsTimeout(IAsyncResult result) {
         if (!Object.ReferenceEquals(result.AsyncState, m_countdownTimer)) return false;
         EndTimeout(result);
         m_countdownTimer = null;
         return true;
      }
      #endregion

      #region Cancellation Methods
      private void ValidateCancelAllowed() {
         if (m_cancelSignal == null)
            throw new InvalidOperationException("AsyncEnumerator object must be created with the CancelAllow option");
      }
      public void SetCancelAlert(Int32 discardMarker) {
         ValidateCancelAllowed();
         m_cancelSignal.BeginAlert(this.End(discardMarker, this.EndCancelAlert), m_cancelSignal);
      }
      private Object EndCancelAlert(IAsyncResult result) {
         return m_cancelSignal.EndAlert(result);
      }
      public void Cancel(Object value) {
         ValidateCancelAllowed();
         m_cancelSignal.Alert(value);
      }
      public Boolean IsCancelAlert(IAsyncResult result) {
         Object cancelValue;
         return IsCancelAlert(result, out cancelValue);
      }
      public Boolean IsCancelAlert(IAsyncResult result, out Object cancelValue) {
         cancelValue = null;
         if (!Object.ReferenceEquals(result.AsyncState, m_cancelSignal)) return false;
         cancelValue = m_cancelSignal.EndAlert(result);
         return true;
      }
      #endregion

      #region Cancelable Async Operation Support
      /// <summary>
      /// Identifies an EndXxx method that takes an IAsyncResult and returns some result
      /// </summary>
      /// <param name="result">The IAsyncResult of the completion operation.</param>
      /// <returns>The EndXxx method's return value.</returns>
      public delegate Object EndObjectXxx(IAsyncResult result);

      /// <summary>
      /// Pass the result of this method to a BegixXxx method's AsyncCallback argument to have a cancelable operation
      /// complete to advance the enumerator.
      /// </summary>
      /// <param name="discardMarker">Identifies an operation sequence number used for cancelation. The number passed must be >= to the last number passed.</param>
      /// <param name="callback">The EndXxx method that must be called when this canceled operation eventually completes.</param>
      /// <returns>The value that should be passed to a BeginXxx method's AsyncCallback argument.</returns>
      public AsyncCallback End(Int32 discardMarker, EndObjectXxx callback) {
         return m_asyncOpCache.Extract(this, discardMarker, callback);
      }


      /// <summary>
      /// Identifies an EndXxx method that takes an IAsyncResult and doesn't return a value
      /// </summary>
      /// <param name="result">The IAsyncResult of the completion operation.</param>
      public delegate void EndVoidXxx(IAsyncResult result);

      /// <summary>
      /// Pass the result of this method to a BegixXxx method's AsyncCallback argument to have a cancelable operation
      /// complete to advance the enumerator.
      /// </summary>
      /// <param name="discardMarker">Identifies an operation sequence number used for cancelation. The number passed must be >= to the last number passed.</param>
      /// <param name="callback">The EndXxx method that must be called when this canceled operation eventually completes.</param>
      /// <returns>The value that should be passed to a BeginXxx method's AsyncCallback argument.</returns>
      public AsyncCallback EndVoid(Int32 discardMarker, EndVoidXxx callback) {
         return m_asyncOpCache.Extract(this, discardMarker, callback);
      }
      #endregion
   }
}


///////////////////////////////////////////////////////////////////////////////


namespace Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading.AsyncProgModel {
   public partial class AsyncEnumerator {
      #region Subroutine Support
      public IAsyncResult BeginSubroutine(IEnumerator<Int32> enumerator, Int32 discardMarker,
         AsyncEnumeratorOptions options, out AsyncEnumerator aeSubroutine) {
         aeSubroutine = new AsyncEnumerator(options);
         return aeSubroutine.BeginExecute(enumerator,
            this.EndVoid(discardMarker, aeSubroutine.EndSubroutine));
      }

      public IAsyncResult BeginSubroutine(IEnumerator<Int32> enumerator, Int32 discardMarker,
         AsyncEnumeratorOptions options) {
         AsyncEnumerator aeSubroutine;
         return BeginSubroutine(enumerator, discardMarker, options, out aeSubroutine);
      }

      public IAsyncResult BeginSubroutine(IEnumerator<Int32> enumerator) {
         return BeginSubroutine(enumerator, Int32.MaxValue, AsyncEnumeratorOptions.None);
      }

      public void EndSubroutine(IAsyncResult result) {
         // The result should be an AsyncResult returned from BeginSubroutine
         AsyncResult asyncResult = (AsyncResult)result;

         // The initiating object is the aeSubroutine AsyncEnumerator
         ((AsyncEnumerator)asyncResult.InitiatingObject).EndExecute(result);
      }



      public IAsyncResult BeginSubroutine<TResult>(IEnumerator<Int32> enumerator, Int32 discardMarker,
         AsyncEnumeratorOptions options, out AsyncEnumerator<TResult> aeSubroutine) {
         aeSubroutine = new AsyncEnumerator<TResult>(options);

         // We pass the non-generic "EndSubroutine" here as I can't get the code to compile passing "EndSubroutine<TResult>"
         // This is OK because the discard code doesn't need the TResult value
         return aeSubroutine.BeginExecute(enumerator,
            this.EndVoid(discardMarker, aeSubroutine.EndSubroutine));
      }

      public IAsyncResult BeginSubroutine<TResult>(IEnumerator<Int32> enumerator, Int32 discardMarker,
         AsyncEnumeratorOptions options) {
         AsyncEnumerator<TResult> aeSubroutine;
         return BeginSubroutine<TResult>(enumerator, discardMarker, options, out aeSubroutine);
      }

      public IAsyncResult BeginSubroutine<TResult>(IEnumerator<Int32> enumerator) {
         return BeginSubroutine<TResult>(enumerator, Int32.MaxValue, AsyncEnumeratorOptions.None);
      }

      public TResult EndSubroutine<TResult>(IAsyncResult result) {
         // The result should be an AsyncResultNoResult returned from BeginSubroutine
         AsyncResult<TResult> asyncResult = (AsyncResult<TResult>)result;

         // The initiating object is the aeSubroutine AsyncEnumerator
         return ((AsyncEnumerator<TResult>)asyncResult.InitiatingObject).EndExecute(result);
      }
      #endregion
   }
}


///////////////////////////////////////////////////////////////////////////////


namespace Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading.AsyncProgModel {
   public partial class AsyncEnumerator {
      private sealed class AsyncOpCache {
         private Stack<AsyncOp> m_stack;

         internal AsyncOpCache() { m_stack = new Stack<AsyncOp>(); }
         internal AsyncOpCache(Int32 capacity) { m_stack = new Stack<AsyncOp>(capacity); }

         private AsyncOp GetCacheObject() {
            // If an object exists in cache, use it; else return a new object
            lock (m_stack) { if (m_stack.Count > 0) return m_stack.Pop(); }
            return new AsyncOp();
         }

         internal void Insert(AsyncOp asyncOp) {
            asyncOp.ClearState();   // So that fields don't keep child objects from getting GC'd
            lock (m_stack) { m_stack.Push(asyncOp); }
         }
         internal AsyncCallback Extract(AsyncEnumerator asyncEnumerator) {
            return GetCacheObject().Prepare(asyncEnumerator);
         }
         internal AsyncCallback Extract(AsyncEnumerator asyncEnumerator, Int32 discardMarker, EndObjectXxx endObjectXxx) {
            return GetCacheObject().Prepare(asyncEnumerator, discardMarker, endObjectXxx);
         }
         internal AsyncCallback Extract(AsyncEnumerator asyncEnumerator, Int32 discardMarker, EndVoidXxx endVoidXxx) {
            return GetCacheObject().Prepare(asyncEnumerator, discardMarker, endVoidXxx);
         }
      }
   }
}


///////////////////////////////////////////////////////////////////////////////


namespace Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading.AsyncProgModel {
   public partial class AsyncEnumerator {
      /// <summary>
      /// Base class that wraps an asynchronous operation and its AsyncCallback method.
      /// </summary>
      [DebuggerStepThrough]
      private class AsyncOp {
         // Delegate referring to this object's AsyncCallback method
         // This delegate is created once and lives the lifetime of the object
         private AsyncCallback m_asyncCallback;

         // The AsyncEnumerator that cares when this operation completes
         private AsyncEnumerator m_asyncEnumerator = null;

         // The operation's discard marker
         private Int32 m_discardMarker = 0;

         // The operation's self-complete method
         private EndObjectXxx m_endObjectXxx = null;  // Identifies an EndXxx method with a non-void return value
         private EndVoidXxx m_endVoidXxx = null;      // Identifies an EndXxx method with a void return value

         // The IAsyncResult of the completed operation
         private IAsyncResult m_asyncResult = null;

         internal AsyncOp() {
            m_asyncCallback = this.AsyncCallback;
         }

         internal void ClearState() {
            m_asyncEnumerator = null;
            m_asyncResult = null;
            m_discardMarker = 0;
            m_endObjectXxx = null;
            m_endVoidXxx = null;
            // NOTE: m_asyncCallback should not be reset to null
         }

         internal AsyncCallback Prepare(AsyncEnumerator asyncEnumerator) {
            m_asyncEnumerator = asyncEnumerator;

            // Non-cancelable ops have the highest marker possible (Int32.MaxValue)
            m_discardMarker = Int32.MaxValue;
            return m_asyncCallback;
         }

         internal AsyncCallback Prepare(AsyncEnumerator asyncEnumerator, Int32 discardMarker, EndObjectXxx endObjectXxx) {
            if (endObjectXxx == null) throw new ArgumentNullException("endObjectXxx");
            m_asyncEnumerator = asyncEnumerator;
            m_discardMarker = discardMarker;
            m_endObjectXxx = endObjectXxx;
            return m_asyncCallback;
         }

         internal AsyncCallback Prepare(AsyncEnumerator asyncEnumerator, Int32 discardMarker, EndVoidXxx endVoidXxx) {
            if (endVoidXxx == null) throw new ArgumentNullException("endVoidXxx");
            m_asyncEnumerator = asyncEnumerator;
            m_discardMarker = discardMarker;
            m_endVoidXxx = endVoidXxx;
            return m_asyncCallback;
         }

         private void AsyncCallback(IAsyncResult result) {
            m_asyncResult = result;
            m_asyncEnumerator.EnqueueCompletedOpToInbox(this);
         }
         internal IAsyncResult AsyncResult { get { return m_asyncResult; } }
         internal Int32 DiscardMarker { get { return m_discardMarker; } }

         /// <summary>
         /// Called when an AsyncOp is being rejected/dicarded to ensure that its EndXxx method is invoked
         /// </summary>
         internal void SelfComplete() {
            try {
               if (m_endObjectXxx != null) m_endObjectXxx(m_asyncResult);
               if (m_endVoidXxx != null) m_endVoidXxx(m_asyncResult);
            }
            catch (Exception) { /* swallow */ }
         }
      }
   }
}


///////////////////////////////////////////////////////////////////////////////


namespace Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading.AsyncProgModel {
   public partial class AsyncEnumerator {
      /// <summary>
      /// This struct contains a single Int32 member that encapsulates the  
      /// number of items the enumerator is waiting for and the number of 
      /// completed async operations in the inbox. All members of this type
      /// manipulate the counters atomically.
      /// </summary>
      [DebuggerStepThrough]
      [DebuggerDisplay("Wait={Wait}, Inbox={Inbox}")]
      protected struct WaitAndInboxCounts {
         #region Private Members
         /// <summary>
         /// Sentinal value used to indicate that a thread determined that 
         /// it should call MoveNext again to advance the iterator 
         /// </summary>
         private const UInt16 c_MaxWait = UInt16.MaxValue;

         /// <summary>
         /// High 16 bits=number of inbox items to wait for before calling MoveNext
         /// Low 16 bits=number of items in inbox 
         /// </summary>
         private Int32 m_waitAndInboxCounts;

         /// <summary>
         /// Gets/Sets the number of items the enumerator is waiting for 
         /// </summary>
         private UInt16 Wait {
            get { return (UInt16)(m_waitAndInboxCounts >> 16); }
            set { m_waitAndInboxCounts = (Int32)((value << 16) | Inbox); }
         }

         /// <summary>
         /// Gets/Sets the number of items in the inbox
         /// </summary>
         private UInt16 Inbox {
            get { return (UInt16)m_waitAndInboxCounts; }
            set { m_waitAndInboxCounts = (Int32)((m_waitAndInboxCounts & 0xFFFF0000) | value); }
         }

         /// <summary>
         /// Constructs a WaitAndInboxCounts instance from an Int32
         /// </summary>
         /// <param name="waic">The Int32 instance.</param>
         private WaitAndInboxCounts(Int32 waic) { m_waitAndInboxCounts = waic; }

         /// <summary>
         /// Converts a WaitAndInboxCounts instance to an Int32
         /// </summary>
         /// <returns>The WaitAndInboxCounts object as an Int32.</returns>
         private Int32 ToInt32() { return m_waitAndInboxCounts; }
         #endregion

         /// <summary>
         /// Initializes the Wait to the sentinal value because we don't want
         /// a thread to MoveNext until the iterator has returned a Wait at least once
         /// </summary>
         internal void Initialize() { Wait = c_MaxWait; }

         /// <summary>
         /// Atomically updates the number of inbox items the enumerator 
         /// wants to wait for and returns the new value.
         /// </summary>
         /// <param name="numberOpsToWaitFor">The number of asynchronous operations that must complete before the enumerator advances.</param>
         /// <returns>Returns true if the calling thread met the requirements necessary to call the enumerator's MoveNext method.</returns>
         internal Boolean AtomicSetWait(UInt16 numberOpsToWaitFor) {
            return InterlockedEx.Morph<Boolean, UInt16>(ref m_waitAndInboxCounts, numberOpsToWaitFor, SetWait);
         }

         [DebuggerStepThrough]
         private static Int32 SetWait(Int32 i, UInt16 numberOpsToWaitFor, out Boolean shouldMoveNext) {
            WaitAndInboxCounts waic = new WaitAndInboxCounts(i);
            waic.Wait = numberOpsToWaitFor;  // Set the number of items to wait for
            shouldMoveNext = (waic.Inbox >= waic.Wait);
            if (shouldMoveNext) {         // Does the inbox contains enough items to MoveNext?
               waic.Inbox -= waic.Wait;   // Subtract the number of items from the inbox
               waic.Wait = c_MaxWait;     // The next wait is indefinite
            }
            return waic.ToInt32();
         }


         /// <summary>
         /// Atomically updates the number of inbox items the enumerator 
         /// wants to wait for and returns the new value. 
         /// </summary>
         /// <returns>Returns true if the calling thread met the requirements necessary to call the enumerator's MoveNext method.</returns>
         internal Boolean AtomicIncrementInbox() {
            return InterlockedEx.Morph<Boolean, Object>(ref m_waitAndInboxCounts, null, IncrementInbox);
         }

         private static Int32 IncrementInbox(Int32 i, Object argument, out Boolean shouldMoveNext) {
            WaitAndInboxCounts waic = new WaitAndInboxCounts(i);
            waic.Inbox++;                 // Add 1 to the inbox count
            shouldMoveNext = (waic.Inbox == waic.Wait);
            if (shouldMoveNext) {         // Does the inbox contain enough items to MoveNext?
               waic.Inbox -= waic.Wait;   // Subtract the number of items from the inbox
               waic.Wait = c_MaxWait;     // The next wait is indefinite
            }
            return waic.ToInt32();
         }

         /// <summary>
         /// Atomically subtracts the number of discarded items from the inbox.
         /// </summary>
         /// <param name="numRemoved">The number of asynchronous operations that were discarded from the inbox.</param>
         internal void AtomicDecrementInbox(Int32 numRemoved) {
            Interlocked.Add(ref m_waitAndInboxCounts, -numRemoved);
         }
      }
   }
}


///////////////////////////////////////////////////////////////////////////////


namespace Microsoft.OfficeCommunicationsServer.Applications.Threading.Threading.AsyncProgModel {
   [DebuggerStepThrough]
   public sealed class AsyncEnumerator<TResult> : AsyncEnumerator {
      #region Instance fields
      // The iterator's result value
      private TResult m_result = default(TResult);
      public TResult Result {
         get { return m_result; }
         set { m_result = value; }
      }
      #endregion

      #region Constructors
      public AsyncEnumerator() : this(AsyncEnumeratorOptions.None) { }
      public AsyncEnumerator(AsyncEnumeratorOptions options) : base(options) { }
      #endregion

      #region Execute, BeginExecute and EndExecute
      new public TResult Execute(IEnumerator<Int32> enumerator) {
         return EndExecute(BeginExecute(enumerator, null, null));
      }

      new public TResult EndExecute(IAsyncResult result) { return ((AsyncResult<TResult>)m_asyncResult).EndInvoke(); }

      protected override AsyncResult OnContructAsyncResult(AsyncCallback callback, Object state) {
         return new AsyncResult<TResult>(callback, state, this);
      }

      protected override void OnCompleteAsyncResult() {
         ((AsyncResult<TResult>)m_asyncResult).SetAsCompleted(m_result, false);
      }
      #endregion

      #region Members called by Iterator
      new public static AsyncEnumerator<TResult> GetAsyncEnumerator() { return (AsyncEnumerator<TResult>)t_thisAsyncEnumerator; }
      #endregion
   }
}


//////////////////////////////// End of File //////////////////////////////////